import TileLayer from 'ol/layer/Tile';
import WMTS from 'ol/source/WMTS';
import ImageWMS from 'ol/source/ImageWMS.js';
import TileArcGISRest from 'ol/source/TileArcGISRest';
import VectorSource from 'ol/source/Vector';
import ImageStatic from 'ol/source/ImageStatic';
import VectorLayer from 'ol/layer/Vector';
import ImageLayer from 'ol/layer/Image';
import LayerGroup from 'ol/layer/Group';
import WMTSTileGrid from 'ol/tilegrid/WMTS';
import { Fill, Stroke, Style } from 'ol/style';
import { get as getProjection } from 'ol/proj';
import { getTopLeft, getWidth } from 'ol/extent';
import Feature from 'ol/Feature';
import Polygon from 'ol/geom/Polygon';
import { fromExtent } from 'ol/geom/Polygon';
import { LinearRing, MultiPolygon } from 'ol/geom';
import GeoJSON from 'ol/format/GeoJSON';

function Layer(map) {
    this.map = map;

    this.maskVectorLayer = null; //遮罩图层
}

/**
 * @description: 初始化图层，影像与矢量
 */
Layer.prototype.initLayer = function () {
    //------------添加影像 全国影像 + arcgis影像
    let img = this.getTianDiTuWmtsLayerByParam('天地图影像', 'img', 'img');
    let cia = this.getTianDiTuWmtsLayerByParam('天地图影像注记', 'cia', 'cia');
    let imgLayerGroup = this.createGroup('影像图层组', 1, [img, cia]);
    imgLayerGroup.setVisible(false);
    this.map.addLayer(imgLayerGroup); //添加影像

    //-------------添加地形 全国地形
    let ter = this.getTianDiTuWmtsLayerByParam('天地图地形', 'ter', 'ter');
    let cta = this.getTianDiTuWmtsLayerByParam('天地图地形注记', 'cta', 'cta');
    let terLayerGroup = this.createGroup('地形图层组', 1, [ter, cta]);
    terLayerGroup.setVisible(false);
    this.map.addLayer(terLayerGroup); //添加地形

    //添加矢量 全国矢量 + arcgis矢量
    let vec = this.getTianDiTuWmtsLayerByParam('天地图矢量', 'vec', 'vec');
    let cva = this.getTianDiTuWmtsLayerByParam('天地图矢量注记', 'cva', 'cva');
    let cvaLayerGroup = this.createGroup('矢量图层组', 1, [vec, cva]);
    this.map.addLayer(cvaLayerGroup); //添加矢量

    return {
        layer: this.map.getLayers().getArray()
    };
};

/**
 * @description: 添加json的边线图层
 * @param {*} jsonData json数据
 */
Layer.prototype.initBoundaryLayer = function (jsonData) {
    // 创建矢量数据源
    const vectorSource = new VectorSource({
        features: new GeoJSON().readFeatures(jsonData)
    });
    // 创建矢量图层并设置样式
    const vectorLayer = new VectorLayer({
        name: '边线图层',
        zIndex: 2,
        source: vectorSource,
        style: new Style({
            fill: new Fill({
                color: 'rgba(255, 255, 255, 0)' //填充为空白（透明）
            }),
            stroke: new Stroke({
                color: '#757173', // 边线颜色
                width: 1
            })
        })
    });
    let layer = this.createGroup('边界图层组', 2, [vectorLayer]);
    this.map.addLayer(layer);
};

/**
 * @description: 根据geojson创建遮罩层
 * @param {*} geoJson 行政区geoJson数据
 * @return {*} 返回geoJson矩形范围
 */
Layer.prototype.initMaskLayer = function (geoJson) {
    if (!this.maskVectorLayer) {
        this.maskVectorLayer = new VectorLayer({
            name: '遮罩图层',
            source: new VectorSource(),
            zIndex: 2,
            declutter: false, //防止标注文字重复标注
            style: new Style({
                fill: new Fill({
                    color: 'rgba( 255, 255, 255, 0.7)'
                }),
                stroke: new Stroke({
                    color: '#f4b49f',
                    width: 3
                })
            })
        });
        this.map.addLayer(this.maskVectorLayer);
    } else {
        this.maskVectorLayer.getSource().clear();
    }

    const jsonReader = new GeoJSON();
    const features = jsonReader.readFeatures(geoJson); //json转feature
    const geom = features[0].getGeometry(); //获取geometry对象
    this.addPolygonHoles(this.maskVectorLayer, geom, {
        strokeColor: 'white',
        strokeWidth: 2,
        fillColor: 'rgba(0,0,0,0.4)'
    });
    return geom.getExtent(); //返回遮罩层矩形范围
};

/**
 * @description: 行政区遮罩（带洞多边形）
 * @param {*} layer 遮罩图层
 * @param {*} holeGeom 行政区多边形
 * @param {*} styleObj 遮罩样式
 * @return {*}
 */
Layer.prototype.addPolygonHoles = function (layer, holeGeom, styleObj = {}) {
    let extent = [-180, -90, 180, 90];
    let polygonRing = fromExtent(extent); //从范围创建多边形
    let coords = holeGeom.getCoordinates(); //获取此几何的坐标数组。该数组具有用于多边形的GeoJSON坐标数组的结构
    if (holeGeom instanceof MultiPolygon)
        coords.forEach((coord) => {
            let linearRing = new LinearRing(coord[0].map(([lon, lat]) => [lon - 0.006, lat]));
            polygonRing.appendLinearRing(linearRing); //将传递的线环添加到这个多边形
        });
    else {
        let linearRing = new LinearRing(coords[0].map(([lon, lat]) => [lon - 0.006, lat]));
        polygonRing.appendLinearRing(linearRing); //将传递的线环添加到这个多边形
    }
    let feature = new Feature({ geometry: polygonRing });
    feature.setStyle(styleFunction(styleObj));
    layer.getSource().addFeature(feature);
};

//创建矢量图层
Layer.prototype.createVectorLayer = function (layerName, zIndex, styleObj, sourceObj, declutter) {
    let _sourceObj = sourceObj == null ? { wrapX: false } : sourceObj;
    let source = new VectorSource(_sourceObj);
    let vectorLayer = new VectorLayer({
        source: source,
        zIndex: zIndex || 10,
        declutter: declutter || false, //防止标注文字重复标注
        style: styleFunction(styleObj)
    });
    vectorLayer.set('layerName', layerName);
    this.map.addLayer(vectorLayer);
    return vectorLayer;
};

/**
 * @description: 创建一个图层组
 * @param {*} LayerGroupName 图层组名称
 * @param {*} zIndex 图层顺序
 * @param {*} layers 图层数组 []
 * @return {*} layerGroup
 */
Layer.prototype.createGroup = function (layerGroupName, zIndex, layers) {
    let layerGroup = new LayerGroup({
        layers: layers,
        zIndex: zIndex || 0
    });
    layerGroup.set('layerName', layerGroupName || '图层组');
    return layerGroup;
};

//样式函数stroke fill
let styleFunction = function (styleObj) {
    let style = {};
    if (styleObj && (styleObj.strokeColor || styleObj.strokeWidth)) {
        style.stroke = new Stroke({
            color: styleObj.strokeColor || '#FFFFFF',
            width: styleObj.strokeWidth || 1
        });
    }
    if (styleObj && styleObj.fillColor) {
        style.fill = new Fill({
            color: styleObj.fillColor || 'rgba(255,255,255,0.5)'
        });
    }
    return new Style(style);
};

/**
 * @description: 获取所有的图层
 * @return {*} 对应图层对象
 */
Layer.prototype.getAllLayers = function () {
    let layerArr = this.map.getLayers().array_;
    return layerArr;
};

/**
 * @description: 根据图层名获取图层
 * @param {string} layerName 图层名称
 * @return {*} 对应图层对象
 */
Layer.prototype.getLayerByName = function (layerName) {
    let layerArr = this.getAllLayers();
    for (let k = 0; k < layerArr.length; k++) {
        if (layerArr[k].values_.layerName == layerName || layerArr[k].layerName == layerName) {
            return layerArr[k];
        }
    }
};

/**
 * @description: 叠加WMTS
 * @param {string} layerName 图层名称
 * @param {string} url 图层路径
 * @param {object} params 参数
 * @return {TileLayer} 图层对象
 */
Layer.prototype.getTianDiTuWmtsLayerByParam = function (layerName, url, type) {
    const token = '3b41248c204d6f92ca4fbd7da0386da6'; //'fe40e8bfa4d16f7a68afafe70ad0483e'
    let m = parseInt(Math.random() * 8); //0-7随机选择
    const img =
        'http://t' +
        m +
        '.tianditu.gov.cn/img_c/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=c&FORMAT=tiles&tk='; //影像底图
    const cia =
        'http://t' +
        m +
        '.tianditu.gov.cn/cia_c/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=c&FORMAT=tiles&tk='; //影像注记
    const vec =
        'http://t' +
        m +
        '.tianditu.gov.cn/vec_c/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=c&FORMAT=tiles&tk='; //影像底图
    const cva =
        'http://t' +
        m +
        '.tianditu.gov.cn/cva_c/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=c&FORMAT=tiles&tk='; //影像注记
    const ter =
        'http://t' +
        m +
        '.tianditu.gov.cn/ter_c/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ter&STYLE=default&TILEMATRIXSET=c&FORMAT=tiles&tk='; //地形底图
    const cta =
        'http://t' +
        m +
        '.tianditu.gov.cn/cta_c/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cta&STYLE=default&TILEMATRIXSET=c&FORMAT=tiles&tk='; //地形标注
    if (!url) return null;
    url = decodeURIComponent(url);
    const projection = getProjection('EPSG:4326');
    const projectionExtent = projection.getExtent();
    const size = getWidth(projectionExtent) / 256;
    const resolutions1 = new Array(19);
    const resolutions = new Array(19);
    const matrixIds = new Array(19);
    for (let z = 0; z < 20; ++z) {
        //1.40625
        resolutions1[z] = size / Math.pow(2, z); //天地图经纬 度底图的计算参数
        resolutions[z] = 1.40625285 / Math.pow(2, z); //苍穹 底图计算参数（可能需要修改，根据点位偏移自己去调整）
        matrixIds[z] = z;
    }
    let source = new WMTS({
        crossOrigin: 'anonymous', //用于存图跨域
        name: layerName,
        url: url,
        layer: type,
        style: 'default',
        matrixSet: 'c',
        format: 'tiles',
        wrapX: true,
        tileGrid: new WMTSTileGrid({
            origin: getTopLeft(projectionExtent),
            resolutions: resolutions,
            matrixIds: matrixIds
        })
    });
    source.setTileUrlFunction(function (data) {
        let tilematrix = data[0];
        let tilecol = data[1];
        let tilerow = data[2];
        let baseUrl = '';
        if (type == 'img') baseUrl = img;
        if (type == 'cia') baseUrl = cia;
        if (type == 'vec') baseUrl = vec;
        if (type == 'cva') baseUrl = cva;
        if (type == 'ter') baseUrl = ter;
        if (type == 'cta') baseUrl = cta;
        return baseUrl + token + `&TILEMATRIX=${tilematrix}&TILECOL=${tilecol}&TILEROW=${tilerow}`;
    });
    let layer = new TileLayer({
        source: source
    });
    // this.map.addLayer(layer);
    return layer;
};

/**
 * @description 切换基础底图
 * @param {String} type - 底图类型，必传
 * @returns {}
 */
Layer.prototype.changeBaseMap = function (type = 'vector') {
    let vector = this.getLayerByName('矢量图层组');
    let image = this.getLayerByName('影像图层组');
    let landform = this.getLayerByName('地形图层组');
    if (type == 'vector') {
        //矢量天地图层
        vector.setVisible(true);
        image.setVisible(false);
        landform.setVisible(false);
    } else if (type == 'image') {
        //影像天地图层
        vector.setVisible(false);
        image.setVisible(true);
        landform.setVisible(false);
    } else if (type == 'landform') {
        //地形天地图层
        vector.setVisible(false);
        image.setVisible(false);
        landform.setVisible(true);
    }
};

/**
 * @description 新建图片图层,根据图片url和矩形范围添加图片到地图
 * @param {String} url - 图片地址，必传
 * @param {Array} extent - 图片矩形范围，必传
 * @param {Number} [opacity] - 透明度，可选
 * @returns {void}
 */
Layer.prototype.setImageLayer = function (url, extent, opacity) {
    if (url && extent) {
        //清除上次静态图片图层
        if (this.imageLayer) {
            this.map.removeLayer(this.imageLayer);
        }
        this.imageLayer = new ImageLayer({
            zIndex: 5,
            opacity: opacity || 1
        });
        this.imageLayer.set('layerName', '静态图片图层');
        this.map.addLayer(this.imageLayer);

        // 更新图片图层的源
        this.imageLayer.setSource(
            new ImageStatic({
                url: url,
                imageExtent: extent
            })
        );
    }
    return this.imageLayer;
};

/**
 * @description 移除图片图层
 * @returns {void}
 */
Layer.prototype.removeImageLayer = function () {
    let layer = {};
    layer = this.getLayerByName('静态图片图层');
    if (layer) {
        this.map.removeLayer(layer);
        this.imageLayer = null;
    }
};

/**
 * @description 添加预警区
 * @param {Array} polygons - 预警区坐标、颜色、等级 对象数组，必传
 * @returns {void}
 */
Layer.prototype.addGridArea = function (polygons) {
    let features = [];
    polygons.forEach((item, index) => {
        if (item) {
            let points = item.points;
            let feature = new Feature({
                geometry: new Polygon([points])
            });
            // 创建样式函数
            let styleFunc = function () {
                return new Style({
                    fill: new Fill({
                        color: Bit32ToHex(item.color)
                    })
                });
            };
            // 设置要素的样式
            feature.setStyle(styleFunc);
            feature.setProperties(item);
            feature.type = '预警区';
            feature.index = index;
            features.push(feature);
        }
    });
    let layer = this.getLayerByName('qxfxyjLayer');
    //先清空图层
    layer.getSource().clear();
    // 将要素添加到矢量图层
    layer.getSource().addFeatures(features);
    let extent = layer.getSource().getExtent();
    extent[0] != Infinity &&
        this.fitExtentPadding({
            extent: extent,
            duration: 1000,
            paddingList: [150, 150, 150, 100]
        });
};

/**
 * @description 颜色转换10-16
 * @param {String} color - 十进制颜色值，必传
 * @returns {void}
 */
let Bit32ToHex = function (color) {
    var htmlColor = '#ffffff';
    color = parseInt(color);
    try {
        var r = (color & 255).toString(16);
        var g = ((color >> 8) & 255).toString(16);
        var b = ((color >> 16) & 255).toString(16);
        htmlColor = '#' + (r.length < 2 ? '0' + r : r) + (g.length < 2 ? '0' + g : g) + (b.length < 2 ? '0' + b : b);
    } catch (e) {
        alert(e.message);
    }
    return htmlColor;
};

/**
 * @description: 添加arcgis瓦片服务图层
 * @param {string} layerName 图层路径名称
 * @param {string} url 图层路径
 * @return {TileLayer} 图层对象
 */
Layer.prototype.getArcgisMapServer = function (layerName, url) {
    if (url) {
        const arcLayer = new TileLayer({
            source: new TileArcGISRest({
                wrapX: false,
                url: url
            })
        });
        if (layerName) {
            arcLayer.set('layerName', layerName);
        }
        return arcLayer;
    }
};

Layer.prototype.setWmsLayer = function (layers, layername) {
    console.log('layercheck', layers, layername);
    let imageLayer = new ImageLayer({
        zIndex: 2,
        source: new ImageWMS({
            ratio: 1,
            url: process.env.VUE_APP_BASE_API + '/geoserverA/geoserver/cite/wms',
            params: {
                //service: 'WMS',
                VERSION: '1.1.0',
                request: 'GetMap',
                LAYERS: layers,
                STYLES: '',
                FORMAT: 'image/png' //通常使用 image/png 格式
            }
        }),
        name: `Layer${layername}`,
        opacity: 1
    });
    imageLayer.set('layerName', `Layer${layername}`);
    this.map.addLayer(imageLayer);
};

//添加Feature到图层中
Layer.prototype.addFeatureToLayer = function (layerName, polygons, style) {
    let layer = this.getLayerByName(layerName);
    if (layer) {
        let features = [];
        polygons.forEach((item, index) => {
            if (item) {
                let feature = new Feature({
                    geometry: new Polygon([item])
                });
                // 创建样式函数
                // 创建样式函数
                let styleFunc = function () {
                    return new Style({
                        fill: new Fill({
                            color: style.fill
                        })
                    });
                };
                // 设置要素的样式
                feature.setStyle(styleFunc);
                feature.type = '预警区裁剪';
                feature.index = index;
                features.push(feature);
            }
        });
        // 将要素添加到矢量图层
        layer.getSource().addFeatures(features);
        return features;
    } else {
        return null;
    }
};

/**
 * @description: 地图放大到某个区域
 * @param {*} extent 范围
 * @param {*} duration 时间
 * @param {*} paddingList 边距
 * @return {*}
 */
Layer.prototype.fitExtentPadding = function (data) {
    this.map.getView().fit(data.extent, {
        duration: data.duration || 0, // 动画持续时间（毫秒）
        padding: data.paddingList || [0, 0, 0, 0] // 可根据需要调整填充值
    });
};

/**
 * @description: 地图放大到某个要素
 * @param {*} feature 要素
 * @param {*} duration 时间
 * @return {*}
 */
Layer.prototype.fitFeature = function (data) {
    this.map.getView().fit(data.feature.getGeometry().getExtent(), {
        duration: data.duration || 0, // 动画持续时间（毫秒）
        padding: data.paddingList || [0, 0, 0, 0] // 可根据需要调整填充值
    });
};

/**
 * @description: 地图放大到某个图层
 * @param {*} layer 图层
 * @param {*} duration 时间
 * @return {*}
 */
Layer.prototype.fitLayer = function (data) {
    this.map.getView().fit(data.layer.getSource().getExtent(), {
        duration: data.duration || 0, // 动画持续时间（毫秒）
        padding: data.paddingList || [0, 0, 0, 0] // 可根据需要调整填充值
    });
};

/**
 * @description: 销毁底图资源
 * @return {*}
 */
Layer.prototype.disposeMap = function () {
    this.map
        .getLayers()
        .getArray()
        .forEach((layer) => {
            // console.log(layer,"layer");
            if (layer instanceof LayerGroup) {
                layer
                    .getLayers()
                    .getArray()
                    .forEach((layer) => {
                        // console.log(layer,"grouplayer");
                        layer.getSource().clear();
                        layer.dispose();
                        this.map.removeLayer(layer);
                    });
            } else {
                let vectorSource = layer.getSource();
                if (vectorSource instanceof VectorSource) {
                    // console.log("vectorSource清除");
                    vectorSource.clear();
                }
                layer.dispose(); // 彻底销毁图层
                this.map.removeLayer(layer);
            }
        });
    this.map.getLayers().clear();
    this.map.setTarget(null); // 解除地图与 DOM 元素的绑定
    this.map.dispose(); // 彻底销毁地图实例
};
export default Layer;
